package me.zhengjie.logging.aspect

import me.zhengjie.common.utils.*
import me.zhengjie.logging.domain.SysLog
import me.zhengjie.logging.service.SysLogService
import org.aspectj.lang.JoinPoint
import org.aspectj.lang.ProceedingJoinPoint
import org.aspectj.lang.annotation.AfterThrowing
import org.aspectj.lang.annotation.Around
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Pointcut
import org.springframework.stereotype.Component

/**
 * @author Kuki Wu
 * @date 2024-11-24
 */
@Component
@Aspect
class LogAspect(private val sysLogService: SysLogService) {
    private var currentTime = 0L

    /**
     * 配置切入点
     */
    @Pointcut("@annotation(me.zhengjie.logging.annotation.Log)")
    fun logPointcut() {
        // 该方法无方法体,主要为了让同类中其他方法使用此切入点
    }

    /**
     * 配置环绕通知,使用在方法logPointcut()上注册的切入点
     *
     * @param joinPoint join point for advice
     */
    @Around("logPointcut()")
    @Throws(Throwable::class)
    fun logAround(joinPoint: ProceedingJoinPoint): Any {
        val result: Any
        currentTime = System.currentTimeMillis()
        result = joinPoint.proceed()
        val log = SysLog("INFO", System.currentTimeMillis() - currentTime)
        val request = RequestHolder.httpServletRequest
        sysLogService.save(username, StringUtils.getBrowser(request), StringUtils.getIp(request), joinPoint, log)
        return result
    }

    /**
     * 配置异常通知
     *
     * @param joinPoint join point for advice
     * @param e exception
     */
    @AfterThrowing(pointcut = "logPointcut()", throwing = "e")
    fun logAfterThrowing(joinPoint: JoinPoint, e: Throwable) {
        val log = SysLog("ERROR", System.currentTimeMillis() - currentTime)
        log.exceptionDetail = ThrowableUtil.getStackTrace(e).toByteArray()
        val request = RequestHolder.httpServletRequest
        sysLogService.save(
            username,
            StringUtils.getBrowser(request),
            StringUtils.getIp(request),
            joinPoint as ProceedingJoinPoint,
            log
        )
    }

    val username: String?
        get() = try {
            SecurityUtils.username
        } catch (e: Exception) {
            ""
        }
}